package com.oozol.lieluyun.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.oozol.lieluyun.config.AppConfig;
import com.oozol.lieluyun.config.BusinessException;
import com.oozol.lieluyun.config.GlobalService;
import com.oozol.lieluyun.entity.BuildHistory;
import com.oozol.lieluyun.entity.BuildJob;
import com.oozol.lieluyun.entity.JenkinsLoginRes;
import com.oozol.lieluyun.entity.JobList;
import com.oozol.lieluyun.entity.UserEntity;
import com.oozol.lieluyun.resultmsg.ResultErrorMsg;
import com.oozol.lieluyun.service.IJenkinsService;
import com.surenpi.jenkins.client.Jenkins;
import com.surenpi.jenkins.client.core.Action;
import com.surenpi.jenkins.client.core.Cause;
import com.surenpi.jenkins.client.core.Parameter;
import com.surenpi.jenkins.client.job.BuildDetail;
import com.surenpi.jenkins.client.job.BuildInfo;
import com.surenpi.jenkins.client.job.GitTagList;
import com.surenpi.jenkins.client.job.Job;
import com.surenpi.jenkins.client.job.JobDetails;
import com.surenpi.jenkins.client.job.Jobs;
import java.net.URI;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

@Service
public class JenkinsServicesImpl implements IJenkinsService {
   @Autowired
   private AppConfig appConfig;
   @Value("${spring.profiles.active}")
   private String springProfilesActive;

   public Jenkins getJenkins() throws Exception {
      URI serverURI = new URI(this.appConfig.getJenkinsServerURI());
      Jenkins jenkins = new Jenkins(serverURI, GlobalService.userEntity.getUsername(), GlobalService.userEntity.getPassword());
      return jenkins;
   }

   public List<BuildHistory> buildHistory(String jobName) throws Exception {
      Jenkins jenkins = this.getJenkins();
      Jobs jobMgr = jenkins.getJobs();
      JobDetails jobDetails = jobMgr.getDetails(jobName);
      List<BuildHistory> buildDetails = new ArrayList();

      for(BuildInfo buildInfo : jobDetails.getBuilds()) {
         List<Action> actions = new ArrayList();
         Action action = new Action();
         BuildHistory buildHistory = new BuildHistory();
         BuildDetail buildDetail = jobMgr.getBuildDetails(jobName, buildInfo.getNumber());
         List<Action> tmp = buildDetail.getActions();
         if (!Objects.equals(tmp, (Object)null)) {
            tmp.forEach((item) -> {
               if (!Objects.equals(item.getParameters(), (Object)null)) {
                  action.setParameters(item.getParameters());
               }

               if (!Objects.equals(item.getCauses(), (Object)null)) {
                  action.setCauses(item.getCauses());
               }

               if (!Objects.equals(item.getLastBuiltRevision(), (Object)null)) {
                  action.setLastBuiltRevision(item.getLastBuiltRevision());
               }

            });
            actions.add(action);
            buildDetail.setActions(actions);
         }

         buildHistory.setStart(buildDetail.getTimestamp());
         buildHistory.setEnd(buildDetail.getTimestamp());
         buildHistory.setBuildNumber(buildDetail.getNumber());
         if (!Objects.equals(buildDetail.getResult(), (Object)null)) {
            buildHistory.setStatus(buildDetail.getResult().getName());
         } else {
            buildHistory.setStatus("BUILDING");
         }

         buildHistory.setBuilder(((Cause)((Action)actions.get(0)).getCauses().get(0)).getUserName());
         if (!Objects.equals(((Action)actions.get(0)).getLastBuiltRevision(), (Object)null)) {
            buildHistory.setCommit(((Action)actions.get(0)).getLastBuiltRevision().getSHA1());
         } else {
            buildHistory.setCommit("-");
         }

         if (((Action)actions.get(0)).getParameters() != null) {
            buildHistory.setPublishType(((Parameter)((Action)actions.get(0)).getParameters().get(1)).getValue());
            buildHistory.setTag(((Parameter)((Action)actions.get(0)).getParameters().get(0)).getValue());
         }
         buildDetails.add(buildHistory);
      }

      return buildDetails;
   }

   public String buildHistoryLog(String jobName, Integer number) throws Exception {
      Jenkins jenkins = this.getJenkins();
      String str = jenkins.getJobs().getLogText(jobName, number);
      return str;
   }

   public Integer buildJob(BuildJob buildJob) throws Exception {
      String jobName = buildJob.getJobName();
      String tagName = buildJob.getTagName();
      String publishType = buildJob.getPublishType();
      Integer number = buildJob.getNumber();
      String apiVersionDeploy = buildJob.getApiVersionDeploy();
      String apiVersionNumber = buildJob.getApiVersionNumber();
      if (!Objects.equals(jobName, (Object)null) && !jobName.isEmpty()) {
         if (!Objects.equals(tagName, (Object)null) && !tagName.isEmpty()) {
            if (!Objects.equals(publishType, (Object)null) && !publishType.isEmpty()) {
               if (Objects.equals(apiVersionDeploy, (Object)null) || apiVersionDeploy.isEmpty()) {
                  apiVersionDeploy = "0";
               }

               if (!Objects.equals(apiVersionDeploy, "1") || !Objects.equals(apiVersionNumber, (Object)null) && !apiVersionNumber.isEmpty()) {
                  Jenkins jenkins = this.getJenkins();
                  if (Objects.equals(publishType, "rollback")) {
                     if (Objects.equals(number, (Object)null)) {
                        throw new BusinessException(ResultErrorMsg._3004);
                     }

                     Jobs jobMgr = jenkins.getJobs();
                     JobDetails jobDetails = jobMgr.getDetails(jobName);
                     if (Objects.equals(jobDetails.getLastBuild().getNumber(), number)) {
                        throw new BusinessException(ResultErrorMsg._3005);
                     }
                  }

                  if (Objects.equals(tagName, "beta")) {
                     Date d = new Date();
                     SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
                     tagName = sdf.format(d);
                  }

                  Map<String, String> params = new HashMap();
                  params.put("TAG_VERSION", tagName);
                  params.put("PUBLISH_TYPE", publishType);
                  params.put("api_version_deploy", apiVersionDeploy);
                  params.put("api_version_number", apiVersionNumber);
                  System.out.println(jobName + " ---------- " + JSON.toJSONString(params));
                  jenkins.getJobs().buildWithParams(jobName, params);
                  return 1;
               } else {
                  throw new BusinessException(ResultErrorMsg._3006);
               }
            } else {
               throw new BusinessException(ResultErrorMsg._3003);
            }
         } else {
            throw new BusinessException(ResultErrorMsg._3002);
         }
      } else {
         throw new BusinessException(ResultErrorMsg._3001);
      }
   }

   public List<String> gitTags(String jobName) throws Exception {
      Jenkins jenkins = this.getJenkins();
      GitTagList gitTagList = jenkins.getJobs().getGitTagList(jobName, "TAG_VERSION");
      List<String> tags = new ArrayList();
      gitTagList.getValues().forEach((item) -> tags.add(item.getValue()));
      Collections.sort(tags);
      Collections.reverse(tags);
      return tags;
   }

   public List<JobList> jobList() throws Exception {
      Jenkins jenkins = this.getJenkins();
      Jobs jobMgr = jenkins.getJobs();
      List<Job> allJobs = jobMgr.getAllJobs();
      List<JobList> jobLists = new ArrayList();
      Set<String> jobSet = new HashSet();
      jobSet.add("erp.build.portal");
      allJobs.forEach((job) -> {
         if (!jobSet.contains(job.getName())) {
            JobList jobList = new JobList();
            jobList.setJobName(job.getName());
            if (Objects.equals(this.springProfilesActive, "prod")) {
               jobList.setJobType("prod");
            } else {
               jobList.setJobType("beta");
            }

            jobLists.add(jobList);
         }

      });
      return jobLists;
   }

   public String jenkinsLogin(UserEntity userEntity) throws Exception {
      String hostUrl = this.appConfig.getJenkinsServerURI();
      String crumb = getJenkinsCrumb(hostUrl, userEntity.getUsername(), userEntity.getPassword());

//      String authorizeUrl = "/j_acegi_security_check";
      String authorizeUrl = "/j_spring_security_check";
      HttpHeaders headers = new HttpHeaders();
      headers.add("Accept", "*/*");
      headers.add("Content-Type", "application/x-www-form-urlencoded");
      headers.add("Referer", hostUrl + authorizeUrl);
      headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36");
      headers.add("Jenkins-Crumb", crumb); // 添加 Crumb 到 Header

      MultiValueMap<String, String> params = new LinkedMultiValueMap();
      params.add("j_username", userEntity.getUsername());
      params.add("j_password", userEntity.getPassword());
      params.add("from", "");
      params.add("Submit", "登录");
      params.add("remember_me", "on");
      RestTemplate restTemplate = new RestTemplate();
      HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity(params, headers);
      ResponseEntity<JenkinsLoginRes> responseEntity = restTemplate.postForEntity(hostUrl + authorizeUrl, requestEntity, JenkinsLoginRes.class, new Object[0]);
      String location = (String)responseEntity.getHeaders().get("Location").get(0);
      String cookies = (String)responseEntity.getHeaders().get("Set-Cookie").get(0);
      if (location.contains("loginError")) {
         return null;
      } else {
         headers.add("Cookie", cookies);
         headers.add("Content-Type", "text/html");
         HttpEntity<MultiValueMap<String, String>> requestEntity2 = new HttpEntity(params, headers);
         restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("utf-8")));
         ResponseEntity<String> exchange = restTemplate.exchange(hostUrl, HttpMethod.GET, requestEntity2, String.class, new Object[0]);
         Document doc = Jsoup.parse(exchange.toString());
//         Element linkb = (Element)doc.select("span").get(1);
         Element linkb = (Element)doc.select("span.jenkins-visually-hidden[data-type=action-label]").get(2);
         String userName = null;
         if (!Objects.isNull(linkb.text())) {
            userName = linkb.text();
         }

         return userName;
      }
   }

   private String getJenkinsCrumb(String hostUrl, HttpHeaders headers) throws Exception {
      RestTemplate restTemplate = new RestTemplate();
      String crumbUrl = hostUrl + "/crumbIssuer/api/json";
      ResponseEntity<Map> responseEntity = restTemplate.exchange(crumbUrl, HttpMethod.GET, new HttpEntity<>(headers), Map.class);

      if (responseEntity.getStatusCode().is2xxSuccessful()) {
         Map<String, Object> body = responseEntity.getBody();
         if (body != null && body.containsKey("crumbRequestField") && body.containsKey("crumb")) {
            String crumbRequestField = (String) body.get("crumbRequestField");
            String crumb = (String) body.get("crumb");
            headers.add(crumbRequestField, crumb);
            return crumb;
         }
      }
      return null;
   }

   public String getJenkinsCrumb(String hostUrl, String username, String password) {
      RestTemplate restTemplate = new RestTemplate();
      String crumbUrl = hostUrl + "/crumbIssuer/api/json";

      HttpHeaders headers = new HttpHeaders();
      headers.setBasicAuth(username, password);

      try {
         ResponseEntity<String> response = restTemplate.exchange(
                 crumbUrl,
                 HttpMethod.GET,
                 new org.springframework.http.HttpEntity<>(headers),
                 String.class
         );

         if (response.getStatusCode().is2xxSuccessful()) {
            String responseBody = response.getBody();
            // 假设返回的 JSON 格式为 {"crumb":"value","crumbRequestField":"Jenkins-Crumb"}
            String crumb = extractCrumbFromResponse(responseBody);
            return crumb;
         } else {
            throw new RuntimeException("Failed to retrieve Jenkins Crumb: " + response.getStatusCode());
         }
      } catch (Exception e) {
         throw new RuntimeException("Error while retrieving Jenkins Crumb", e);
      }
   }

   private String extractCrumbFromResponse(String responseBody) {
      // 使用 JSON 解析库（如 Jackson 或 Gson）提取 Crumb 值
      try {
         ObjectMapper objectMapper = new ObjectMapper();
         JsonNode jsonNode = objectMapper.readTree(responseBody);
         return jsonNode.get("crumb").asText();
      } catch (Exception e) {
         throw new RuntimeException("Failed to parse Crumb response", e);
      }
   }
}
